/*
 * ds18b20.c
 *
 *  Created on: May 13, 2023
 *      Author: zhulijun
 */

#include "my_inc.h"

typedef struct w1_gpio_s
{
	GPIO_TypeDef       *group;
	uint16_t            pin;	//PA12
}w1_gpio_t;

static w1_gpio_t   W1Dat =  /* IO pin connected to PA12 */
{
		.group = GPIOA,
		.pin   = GPIO_PIN_12,
};


#define W1DQ_Input()   \
{  \
		GPIO_InitTypeDef    GPIO_InitStruct = {0};\
		GPIO_InitStruct.Pin   = W1Dat.pin;   \
		GPIO_InitStruct.Mode  = GPIO_MODE_INPUT;   \
		GPIO_InitStruct.Pull  = GPIO_PULLUP;   \
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;  \
		HAL_GPIO_Init(W1Dat.group, &GPIO_InitStruct);   \
}

#define W1DQ_Output()   \
{  \
		GPIO_InitTypeDef    GPIO_InitStruct = {0};\
		GPIO_InitStruct.Pin   = W1Dat.pin;   \
		GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;   \
		GPIO_InitStruct.Pull  = GPIO_NOPULL;   \
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;  \
		HAL_GPIO_Init(W1Dat.group, &GPIO_InitStruct);   \
}


#define W1DQ_Write(x)      HAL_GPIO_WritePin(W1Dat.group, W1Dat.pin,\
								(x==1) ? GPIO_PIN_SET : GPIO_PIN_RESET)

#define W1DQ_Read()        HAL_GPIO_ReadPin(W1Dat.group, W1Dat.pin)


/* Master issues reset pulse and DS18B20 respond with presence pulse*/
uint8_t  DS18B20_Reset(void)
{
	uint8_t       rv = 0;
	uint8_t       retry;


	/* Setup W1 DQ pin as output and high level */
	W1DQ_Output();
	W1DQ_Write(1);
	delay_us(2);

	/* Reset pulse by pulling the DQ pin low>=480 */
	W1DQ_Write(0);
	delay_us(480);

	/* Master releases bus to high when DS18B20 detects this rising edge, it wait 15us to 60us */
	W1DQ_Write(1);
	delay_us(60);

	/* Then DS18B20 transmits a presence pulse by pulling the W1 bus low for 60us to 240us */
	while(W1DQ_Read() && retry < 240)
	{
		retry++;
		delay_us(1);
	}

	if(retry >= 240)
		rv = 1;

	delay_us(240);

	/* Master Rx time must >= 490us */
	W1DQ_Output();
	W1DQ_Write(1);
	delay_us(240);

	return rv;
}


void DS18B29_WriteByte(uint8_t byte)
{
	uint8_t      i = 0;


	W1DQ_Output();

	for(i=0; i<8; i++)
	{
		/* Write 1: pull low<=15us; Write 0: pull low 15~16us  */
		W1DQ_Write(0);
		delay_us(10);

		/* DS18B20 bit sent by LSB (lower bit first) */
		if(byte & 0x1)
			W1DQ_Write(1);
		else
			W1DQ_Write(0);

		/* Write 1/0 slot both>=60us, hold the level for 60us */
		delay_us(60);

		/* Release W1 bus to high */
		W1DQ_Write(1);
		delay_us(2);

		/* Prepare for next bit */
		byte >>= 1;

	}
}

uint8_t DS18B20_ReadByte(void)
{
	uint8_t       i =0;
	uint8_t       byte = 0;


	for(i=0; i<8; i++)
	{
		/*  Read time slot is initiated by mater pulling the W1 bus
		 * low for minimum of 1us and then releasing the bus */
		W1DQ_Output();
		W1DQ_Write(0);
		delay_us(2);

		W1DQ_Write(1);
		delay_us(2);


		/* After master initiates read time slot, DS18B20 will begin
		 * transmitting a 1 or 0 on bus  */
		W1DQ_Input();

		/*DS18B20 bit sent by LSB(lower bit first) */
		if( W1DQ_Read() )
			byte |= 1<<i;

		/* Read slot for >= 60us */
		delay_us(60);

		/* Release W1 bus to high */
		W1DQ_Output();
		W1DQ_Write(1);
		delay_us(2);
	}
	return byte;
}


static inline int DS18B20_Start_Convert(void)
{
	/* Master issues reset pulse and DSQ8B20 respond with presence pulse */
	if( 0 != DS18B20_Reset() )
		return -1;

	/* Master issues Skip ROM command */
	DS18B29_WriteByte(0xCC);

	/* Master issues Convert T command */
	DS18B29_WriteByte(0x44);

	return 0;
}


static inline int DS18B20_Start_Read(uint8_t *buf, int byte)
{
	/* Master issues reset pulse and DSQ8B20 respond with presence pulse */
	if( 0 != DS18B20_Reset() )
			return -1;

	/* Master issues Skip ROM command */
	DS18B29_WriteByte(0xCC);

	/* Master issues Read Scratchpad command */
	DS18B29_WriteByte(0xBE);

	buf[0] = DS18B20_ReadByte();  /* Temperature LSB */
	buf[1] = DS18B20_ReadByte();  /* Temperature MSB */

	/* Don't care followed 7 bytes data */

	return 0;
}


int DS18B20_SampleData(float *temperature)
{
	uint8_t         byte[2];
	uint8_t         sign;
	uint16_t        temp;


	if( !temperature)
		return -1;

	if( 0 != DS18B20_Start_Convert())
		return -2;

	if( 0 != DS18B20_Start_Read(byte, 2))
		return -3;

	/* Temperature byte[0] is LSB, byte[1] is MSB, total 16 bit
	 * Byte[0]: bit[3；0]: decimal bits, bit[7:4]: integer bits
	 * Byte[1]: bit[2:0]: integer bits, bit[7:3]: sign bits
	 */
	if( byte[1] > 0x7) /* bit[7:3] is 1*/
	{
		temp = ~(byte[1]<<8 | byte[0]) + 1;  //补码
		sign = 0;    //温度为负
	}
	else
	{
		sign = 1;   //温度为正
		temp = byte[1]<<8 | byte[0];
	}

	/* byte[1] 的低三位和byte[0] 的高位组成温度值的整数部分，
	 * 而byte[0[的低四位为小数精度备份，且精度系数为0.065 */
	*temperature = (temp>>4) + (temp&0xF)*0.065;
	if( !sign )
	{
		*temperature = -*temperature;
	}

	return 0;

}





































